package net.moonbiter.ebs.protocols.httpjava.client;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.Map;

import net.moonbiter.OperationFailureException;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;

public class ServiceInvoker {
	
	public static final String RESULT_KEY = "result";
	public static final String ERROR_KEY = "error";
	
	private String serverUrl;
	
	public ServiceInvoker(String serverUrl){
		this.serverUrl = serverUrl;
	}
	
	public Object invoke(String providerName, String serviceName, Map<String,Object> serviceParams) throws IOException, IncorrectServerResponseException, OperationFailureException, ClassNotFoundException {
		String url = serverUrl+"/"+providerName+"/"+serviceName+".ebs";
		return ServiceInvoker.invoke(url,serviceParams);
	}
	
	public static Object invoke(String url, Map<String,Object> serviceParams) throws IOException, IncorrectServerResponseException, OperationFailureException, ClassNotFoundException
	{
		HttpClient client = new HttpClient(); 
	
		PostMethod method = new PostMethod(url);	
		
		RequestEntity reqEntity = new SerializedObjectRequestEntity(serviceParams);
		method.setRequestEntity(reqEntity);
		try {
			client.executeMethod(method);			
			InputStream is = method.getResponseBodyAsStream();
			
			//byte[] responseBody = method.getResponseBody();
			//ByteArrayInputStream is = new ByteArrayInputStream(responseBody);
			ObjectInputStream ois = new ObjectInputStream(is);
			Object response = ois.readObject();
			
			if (response instanceof Map){
				Map<?,?> rawResultMap = (Map<?,?>)response;
				if (rawResultMap.containsKey(ERROR_KEY)){
					Object errorObj = rawResultMap.get(ERROR_KEY);
					if (!(errorObj instanceof Exception)){
						throw new IncorrectServerResponseException(url,"error is not an exception");
					}
					Exception error = (Exception)errorObj;
					throw new OperationFailureException("service invokation",error);
				} else if (rawResultMap.containsKey(RESULT_KEY)){
					Object resultObj = rawResultMap.get(RESULT_KEY);
					return resultObj;
				} else {
					throw new IncorrectServerResponseException(url,"no result nor error provided");
				}
				
			} else {
				throw new IncorrectServerResponseException(url,"no map returned as expected");
			}
			
		} finally {
			if (method!=null) {
				method.releaseConnection();
			}
		}
	}
}
